#include "gtkshortcuttrigger.h"
#include "gtkaccelgroupprivate.h"
+#include "gtkprivate.h"
typedef struct _GtkShortcutTriggerClass GtkShortcutTriggerClass;
gboolean enable_mnemonics)
{
GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
- GdkModifierType modifiers;
+ guint keycode;
+ GdkModifierType state;
+ GdkModifierType mask;
+ int group;
+ GdkKeymap *keymap;
guint keyval;
+ int effective_group;
+ int level;
+ GdkModifierType consumed_modifiers;
+ GdkModifierType shift_group_mask;
+ gboolean group_mod_is_accel_mod = FALSE;
+ const GdkModifierType xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK;
+ const GdkModifierType vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK;
+ GdkModifierType modifiers;
if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
- /* XXX: This needs to deal with groups */
- modifiers = gdk_event_get_modifier_state (event);
- keyval = gdk_key_event_get_keyval (event);
-
- if (keyval == GDK_KEY_ISO_Left_Tab)
- keyval = GDK_KEY_Tab;
- else
- keyval = gdk_keyval_to_lower (keyval);
+ mask = gtk_accelerator_get_default_mod_mask ();
+
+ keycode = gdk_key_event_get_keycode (event);
+ state = gdk_event_get_modifier_state (event);
+ group = gdk_key_event_get_group (event);
+ keymap = gdk_display_get_keymap (gdk_event_get_display (event));
+
+ /* We don't want Caps_Lock to affect keybinding lookups.
+ */
+ state &= ~GDK_LOCK_MASK;
+
+ _gtk_translate_keyboard_accel_state (keymap,
+ keycode, state, mask, group,
+ &keyval,
+ &effective_group, &level,
+ &consumed_modifiers);
+
+ /* if the group-toggling modifier is part of the default accel mod
+ * mask, and it is active, disable it for matching
+ */
+ shift_group_mask = gdk_keymap_get_modifier_mask (keymap,
+ GDK_MODIFIER_INTENT_SHIFT_GROUP);
+ if (mask & shift_group_mask)
+ group_mod_is_accel_mod = TRUE;
+
+ gdk_keymap_map_virtual_modifiers (keymap, &mask);
+ gdk_keymap_add_virtual_modifiers (keymap, &state);
+
+ modifiers = self->modifiers;
+ if (gdk_keymap_map_virtual_modifiers (keymap, &modifiers) &&
+ ((modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) ||
+ (modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods)))
+ {
+ /* modifier match */
+ GdkKeymapKey *keys;
+ int n_keys;
+ int i;
+ guint key;
+
+ /* Shift gets consumed and applied for the event,
+ * so apply it to our keyval to match
+ */
+ key = self->keyval;
+ if (self->modifiers & GDK_SHIFT_MASK)
+ key = gdk_keyval_to_upper (key);
+
+ if (keyval == key && /* exact match */
+ (!group_mod_is_accel_mod ||
+ (state & shift_group_mask) == (self->modifiers & shift_group_mask)))
+ return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
+
+ gdk_keymap_get_entries_for_keyval (keymap,
+ self->keyval,
+ &keys, &n_keys);
+
+ for (i = 0; i < n_keys; i++)
+ {
+ if (keys[i].keycode == keycode &&
+ keys[i].level == level &&
+ /* Only match for group if it's an accel mod */
+ (!group_mod_is_accel_mod ||
+ keys[i].group == effective_group))
+ {
+ /* partial match */
+ g_free (keys);
+
+ return GTK_SHORTCUT_TRIGGER_MATCH_PARTIAL;
+ }
+ }
+
+ g_free (keys);
+ }
- if (keyval != self->keyval || modifiers != self->modifiers)
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
- return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
+ return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
}
static guint
static void
test_trigger_trigger (void)
{
- GtkShortcutTrigger *trigger1, *trigger2, *trigger3, *trigger4;
+ GtkShortcutTrigger *trigger[4];
GdkDisplay *display;
GdkSurface *surface;
GdkDevice *device;
{ GDK_KEY_u, GDK_SHIFT_MASK, FALSE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE } },
{ GDK_KEY_u, GDK_SHIFT_MASK, TRUE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT, GTK_SHORTCUT_TRIGGER_MATCH_EXACT } },
};
- int i;
+ int i, j;
- trigger1 = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
- trigger2 = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
- trigger3 = gtk_mnemonic_trigger_new (GDK_KEY_u);
- trigger4 = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger2),
- gtk_shortcut_trigger_ref (trigger3));
+ trigger[0] = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
+ trigger[1] = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
+ trigger[2] = gtk_mnemonic_trigger_new (GDK_KEY_u);
+ trigger[3] = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger[1]),
+ gtk_shortcut_trigger_ref (trigger[2]));
display = gdk_display_get_default ();
device = gdk_seat_get_keyboard (gdk_display_get_default_seat (display));
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
+ GdkKeymapKey *keys;
+ int n_keys;
+
+ if (!gdk_keymap_get_entries_for_keyval (gdk_display_get_keymap (display),
+ tests[i].keyval, &keys, &n_keys))
+ continue;
+
event = gdk_event_key_new (GDK_KEY_PRESS,
surface,
device,
GDK_CURRENT_TIME,
tests[i].state,
tests[i].keyval,
- 0,
- 0,
- 0,
+ keys[0].keycode,
+ keys[0].keycode,
+ keys[0].group,
FALSE);
- g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger1, event, tests[i].mnemonic), ==, tests[i].result[0]);
- g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger2, event, tests[i].mnemonic), ==, tests[i].result[1]);
- g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger3, event, tests[i].mnemonic), ==, tests[i].result[2]);
- g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger4, event, tests[i].mnemonic), ==, tests[i].result[3]);
+ for (j = 0; j < 4; j++)
+ g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger[j], event, tests[i].mnemonic), ==, tests[i].result[j]);
gdk_event_unref (event);
}
g_object_unref (surface);
- gtk_shortcut_trigger_unref (trigger1);
- gtk_shortcut_trigger_unref (trigger2);
- gtk_shortcut_trigger_unref (trigger3);
- gtk_shortcut_trigger_unref (trigger4);
+ gtk_shortcut_trigger_unref (trigger[0]);
+ gtk_shortcut_trigger_unref (trigger[1]);
+ gtk_shortcut_trigger_unref (trigger[2]);
+ gtk_shortcut_trigger_unref (trigger[3]);
}
static int callback_count;